const SFCScriptBlock = require('@vue/compiler-sfc')
const SFCDescriptor = require('@vue/compiler-sfc')
const {relPropsAnnotation} = require("./relAnnotation");
const {getPropsNode, getNodeValue} = require("./relNode");

// Node.type TSUnionType:ts联合类型, TSTypeReference:引用类型, ImportDeclaration:引入的声明, ExpressionStatement:表达式语句如defineProps, ExportDefaultDeclaration:默认导出声明

// 声明式获取
// 1. 从script中获取默认返回节点，并拿取声明（declaration）
// 2. 获取声明的属性（properties）属性有props、data、methods等
// 3. 获取 props 节点，根据节点的key.name判断
// 4. 获取 props 节点内容中的属性
// console.log(zz.scriptAst[0].declaration.properties[0].value.properties)

// setup 获取
// 1. 取type:ExpressionStatement节点
// 2. 拿expression
// 3. 获取defineProps的参数（arguments）
// 4. 获取参数属性（properties）
// 5. 获取属性内容（value）
// 6. 获取属性内容的类型（typeAnnotation）
// 7. 获取属性内容类型的参数（typeParameters）
// 8. 拿内容类型参数类型
// console.log(zz.scriptSetupAst[2].expression.arguments[0].properties[0].value.typeAnnotation.typeParameters.params[0])
// console.log(zz.scriptSetupAst[1].expression.arguments[0].properties[0].value.typeAnnotation.typeParameters.params[0].types)
// console.log(zz.scriptSetupAst[2].expression.arguments[0].properties[3].value.typeAnnotation.typeParameters.params[0])

// 解析ts类型参数
function relTSTypeParam(prop, typeParam, scriptContent) {
    if (typeParam.type === 'TSLiteralType') {
        if (typeParam.literal.type === 'StringLiteral') {
            return "'" + typeParam.literal.value + "'";
        }
        // 文字类型
        return typeParam.literal.value
    } else if (typeParam.type === 'TSUnionType') {
        // 联合类型
        const types = []
        for (let type of typeParam.types) {
            const typeRes = relTSTypeParam(prop, type, scriptContent)
            if (typeRes) {
                types.push(typeRes)
            }
        }
        return types.join(" | ")
    } else if (typeParam.type === 'TSArrayType') {
        // 数组类型
        // console.log(prop.value.typeAnnotation.typeParameters)
        return relTSTypeParam(prop, typeParam.elementType, scriptContent) + '[]'
    } else if (typeParam.type === 'TSTypeReference') {
        // 引用类型
        // todo 解析定义的 type
        return "~" + typeParam.typeName.name + "~"
    } else if (typeParam.type.startsWith('TS') && typeParam.type.endsWith('Keyword')) {
        // ts类型关键字
        // console.log(typeParam)
        const endIndex = typeParam.type.indexOf('Keyword')
        return typeParam.type.substring(2, endIndex).toLowerCase()
    } else if (typeParam.type === 'TSParenthesizedType') {
        // ts括号类型，如(1|2)[]
        return '(' + relTSTypeParam(prop, typeParam.typeAnnotation, scriptContent) + ')'
    } else if (typeParam.type === 'TSFunctionType') {
        // ts 函数类型
        return scriptContent.substring(typeParam.start, typeParam.end)
    }
    return null;
}

// 解析最基础的 Vue 属性类型
function relBaseVueType(props) {
    if (props.value.type === 'Identifier') {
        // 如果是最基础类型，则直接赋值
        return props.value.name
    } else if (props.value.type === 'ArrayExpression') {
        // 如果是数组形式，如 [String, Number]，则循环取值
        const propsElements = props.value.elements
        const propsArrayList = []
        if (propsElements && propsElements.length > 0) {
            for (let propsElement of propsElements) {
                if (propsElement.type === 'Identifier') {
                    propsArrayList.push(propsElement.name)
                }
            }
        }
        return propsArrayList.join(' | ')
    }
    return ''
}

// 解析对象声明的属性
function relPropsObject(propsInfo, prop, scriptContent) {
    // 如果是对象，则解析对象中内容
    const objProperties = prop.value.properties;
    for (let objProperty of objProperties) {
        if (objProperty.key.name === 'type') {
            // type属性
            if (objProperty.value.type === 'TSAsExpression') {
                // 如果内容是ts声明类型，则通过类型参数获取类型
                propsInfo.type = objProperty.value.expression.name
                propsInfo.tsType = relTSTypeParam(objProperty, objProperty.value.typeAnnotation.typeParameters.params[0], scriptContent)
            } else {
                propsInfo.type = relBaseVueType(objProperty)
            }
        } else if (objProperty.key.name === 'default') {
            if (objProperty.value) {
                // 默认属性
                if (objProperty.value.type === 'FunctionExpression' || objProperty.value.type === 'ArrowFunctionExpression') {
                    // 常规函数和箭头函数
                    const valueBody = objProperty.value.body
                    if (!valueBody) {
                        // 没有函数体则为无效的内容
                        continue
                    }
                    if (valueBody.type === 'BlockStatement') {
                        // 如果是内容是块，则取块内容
                        if (valueBody.body && valueBody.body.length > 0) {
                            if (valueBody.body[0].type === 'ReturnStatement') {
                                // 如果是直接返回一个内容，则取该内容
                                propsInfo.default = getNodeValue(valueBody.body[0].argument)
                            } else {
                                // 否则截取函数
                                propsInfo.default = scriptContent.substring(objProperty.value.start, objProperty.value.end)
                            }
                        } else {
                            // 如果没有内容，则直接截取内容块
                            propsInfo.default = scriptContent.substring(valueBody.start, valueBody.end).trim()
                        }
                    } else if (valueBody.type === 'ObjectExpression') {
                        propsInfo.default = scriptContent.substring(valueBody.start, valueBody.end)
                    } else if (valueBody.type === 'ArrayExpression') {
                        if (valueBody.elements && valueBody.elements.length > 0) {
                            const valueList = []
                            for (let element of valueBody.elements) {
                                valueList.push(getNodeValue(element))
                            }
                            propsInfo.default = JSON.stringify(valueList)
                        }
                    } else {
                        propsInfo.default = getNodeValue(valueBody)
                    }
                } else {
                    // 非函数形式直接赋值
                    propsInfo.default = getNodeValue(objProperty.value)
                }
            }
        } else if (objProperty.key.name === 'required') {
            // 必须属性
            propsInfo.required = objProperty.value.value
        }
    }
}

// 解析 props 的属性
function relPropsProperties(properties, scriptContent) {
    const propsMap = {}
    for (const props of properties) {
        const propsInfo = {
            type: '',
            tsType: '',
            default: '',
            desc: '',
            comments: [],
            required: false
        }
        // 解析注释
        const leadingComments = props.leadingComments
        if (leadingComments && leadingComments.length > 0) {
            propsInfo.desc = leadingComments[0].value
            leadingComments.forEach((comment, index) => {
                if (index !== 0) {
                    propsInfo.comments.push(comment.value)
                }
            })
        }
        if (props.value.type === 'ObjectExpression') {
            // 如果是对象，则解析对象中内容
            relPropsObject(propsInfo, props, scriptContent)
        } else if (props.value.type === 'TSAsExpression') {
            propsInfo.type = props.value.expression.name
            // ts声明类型，获取类型注释
            const typeAnnotation = props.value.typeAnnotation
            // 获取类型参数，因为是 PropType 应该只有一个类型参数
            const typeParameter = typeAnnotation.typeParameters.params[0]
            propsInfo.tsType = relTSTypeParam(props, typeParameter, scriptContent)
        } else {
            propsInfo.type = relBaseVueType(props)
        }
        propsMap[props.key.name] = propsInfo;
    }
    return propsMap
}

/**
 * 解析Vue.Props
 * @param {SFCScriptBlock} scriptBlock vue解析后的Script块
 * @param {SFCDescriptor} descriptor vue格式化后的代码
 * @return {
 * {[string]: {
 *     type: string,
 *     tsType: string,
 *     default: string,
 *     desc: string,
 *     comments: [],
 *     required: boolean
 * }} | null}
 */
function relProps(scriptBlock, descriptor) {
    // props 属性
    let properties = null;
    // script 内容
    let scriptContent = ''
    // props 节点
    const propsNode = getPropsNode(scriptBlock)
    if (!propsNode) {
        return null
    }
    if (scriptBlock.scriptAst) {
        // 声名式
        scriptContent = descriptor.script.content
        properties = propsNode.value.properties
    } else if (scriptBlock.scriptSetupAst) {
        // setup形式
        scriptContent = descriptor.scriptSetup.content
        if (propsNode.arguments && propsNode.arguments.length > 0) {
            properties = propsNode.arguments[0].properties
        }
    }
    if (properties) {
        return relPropsProperties(properties, scriptContent)
    }
    return null
}

exports.getPropsNode = getPropsNode
exports.relProps = relProps
